Framework / DOM / Documents / Hit Testing
In This Topic
    Hit Testing
    In This Topic
     Hit Testing Overview

    The DOM is hit-tested by specific visitors that derive from the NDisplayVisitor class, and thus inherit the transform and clip management provided by it, as explained in the The Visual Tree topic. There are generally two types of hit tests that can be performed upon the visual tree:

    • by point - hit test by point is performed by hit test visitors that derive from the NPointHitTestVistior abstract class.
      Visuals that can be hit tested by point need to override the: bool HitTest(NPointHitTestVisitor visitor) virtual method and return true, if they are hit by the hit-test point.
    • by region - hit test by region is performed by hit test visitors that derive from the NRegionHitTestVistior abstract class.
      Visuals that can be hit tested by region need to override the: bool HitTest(NRegionHitTestVisitor visitor) virtual method and return true, if they are hit by the hit-test region.

    Both types of hit-tests can be performed in two variations:

    • top-most - in this variation of hit-testing, the hit-testing of the visual subtree stops when the top-most hit visual is found. This hit-test variation is often used with the by point hit-test type, meaning that the hit test returns the top-most visual below the specified point.
    • all - in this variation of hit-testing, the hit-testing accumulates all visuals that are considered hit. This hit-test variation is often used with the by region hit-test type, meaning that the hit test returns a list of all the visuals that are hit by the specified region.

    Hit-testing is performed by different static methods of the NVisualTreeHelpers static class.

     Hit-Testing Visual Subtrees

    As mentioned, hit-testing is performed by different static methods of the NVisualTreeHelpers static class. A common requirement for all hit-test methods is that they must receive a valid NVisual instance, which to consider as root for the subtree hit-test. The following code performs a visual subtree tree hit-test by point:

    My First Hit-Test
    Copy Code
    // hit test the visual subtree, rooted by sutreeRootVisual by point
    // the point is considered to be in sutreeRootVisual coordinates
    NVisual topMostHit = NVisualTreeHelpers.HitTestTopMostByPoint(sutreeRootVisual, new NPoint(10, 10));
    

    The following table summarizes the hit test static methods exposed by the NVisualTreeHelpers static class

    Method Description

    Top Most - By Point

    NVisual HitTestTopMostByPoint(NVisual visualRoot, NPoint pointInRoot)

    Hit tests the visual tree rooted by visualRoot by point and returns the top-most hit visual.

    NVisual HitTestTopMostByPoint(NVisual visualRoot, NPoint pointInRoot, INFilter<NVisual> filter)

    Hit tests the visual tree rooted by visualRoot by point and returns the top-most hit visual. Optionally you can specify a filter (see filter and clip comments below).

    NVisual HitTestTopMostByPoint(NVisual visualRoot, NPoint pointInRoot, INFilter<NVisual> filter, NRegion clipInRoot)

    Hit tests the visual tree rooted by visualRoot by point and returns the top-most hit visual. Optionally you can specify a filter and clip (see filter and clip comments below).

    Top Most - By Region

    NVisual HitTestTopMostByRegion(NVisual visualRoot, NRegion regionInRoot)

    Hit tests the visual tree rooted by visualRoot by the region defined by the regionInRoot graphics path and returns the top-most hit visual.

    NVisual HitTestTopMostByRegion(NVisual visualRoot, NRegion regionInRoot, INFilter<NVisual> filter)

    Hit tests the visual tree rooted by visualRoot by the region defined by the regionInRoot graphics path and returns the top-most hit visual. Optionally you can specify a filter (see filter and clip comments below).

    NVisual HitTestTopMostByRegion(NVisual visualRoot, NRegion regionInRoot, INFilter<NVisual> filter, NRegion clipInRoot)

    Hit tests the visual tree rooted by visualRoot by the region defined by the regionInRoot graphics path and returns the top-most hit visual. Optionally you can specify a filter and clip (see filter and clip comments below).

    All - By Point

    NList<NVisual> HitTestAllByPoint(NVisual visualRoot, NPoint pointInRoot)

    Hit tests all visuals that reside in the visual tree rooted by visualRoot and returns the hit ones.

    NList<NVisual> HitTestAllByPoint(NVisual visualRoot, NPoint pointInRoot, INFilter<NVisual> filter)

    Hit tests all visuals that reside in the visual tree rooted by visualRoot and returns the hit ones. Optionally you can specify a filter (see filter and clip comments below).

    NList<NVisual> HitTestAllByPoint(NVisual visualRoot, NPoint pointInRoot, INFilter<NVisual> filter, NRegion clipInRoot)

    Hit tests all visuals that reside in the visual tree rooted by visualRoot and returns the hit ones. Optionally you can specify a filter and clip (see filter and clip comments below).

    All - By Region

    NList<NVisual> HitTestAllByRegion(NVisual visualRoot, NRegion regionInRoot)

    Hit tests all visuals that reside in the visual tree rooted by visualRoot by the region defined by the regionInRoot graphics path and returns the hit ones.

    NList<NVisual> HitTestAllByRegion(NVisual visualRoot, NRegion regionInRoot, INFilter<NVisual> filter)

    Hit tests all visuals that reside in the visual tree rooted by visualRoot by the region defined by the regionInRoot graphics path and returns the hit ones. Optionally you can specify a filter (see filter and clip comments below).

    NList<NVisual> HitTestAllByRegion(NVisual visualRoot, NRegion regionInRoot, INFilter<NVisual> filter, NRegion clipInRoot)

    Hit tests all visuals that reside in the visual tree rooted by visualRoot by the region defined by the regionInRoot graphics path and returns the hit ones. Optionally you can specify a filter and clip (see filter and clip comments below).

    As seen from the API table, each hit-test method has two overloads that allow you to optionally specify a filter and a clipping region:

    Filter - the filter is used to determine which visuals should at all be hit-tested. A value of null means that the hit-test is not filtered and hence all visuals that reside in the visualRoot need to be hit-tested. If a valid filter is provided, the respective hit test will only hit-test the visuals that pass the filter (e.g. the Filter method for this visuals returns true - see Filters for more information).

    Clip Region - the clip region is used to additionally limit the area from the visualRoot coordinate space that should be hit-tested. A value of null means that the hit-tested area of the visualRoot coordinate space is not additionally limited. When a hit-test visitor traverses the visual tree it automatically takes into account the currently accumulated clip, as described in the The Visual Tree topic.

     Implementing HitTest Methods

    In order for a visual to be hit by a point or region hit test, its respective HitTest method must return true, if the visual is hit by a point or region respectively. By default a NVisual does not provide an implementation for these methods (they simply return false) - so it is up to derived classes to override the respective HitTest methods, if they need to be hit-tested by point or by region. The rest of this section gives you some tips on how to implement/override the HitTest methods:

    Implementing Point Hit-Test

    As mentioned the bool HitTest(NPointHitTestVisitor visitor) method is called during top-most or all point hit tests. The passed NPointHitTestVisitor instance derives from NDisplayVisitor, and the hit-test point is available in two coordinate systems - local and scene, via the LocalHitTestPoint and SceneHitTestPoint properties respectively. In most cases you will use the point in local coordinates to perform a point hit test over a region in local coordinates. The following code hit-tests a graphics path that represents a doughnut shape by point:

    Implementing Point Hit Test
    Copy Code
    public class MyFirstVisual : NVisual
    {
    ...
     public override bool HitTest(NPointHitTestVisitor visitor)
     {
      NGraphicsPath path = new NGraphicsPath();
      path.AddEllipse(0, 0, 100, 100);
      path.AddEllipse(10, 10, 80, 80);
      return path.Contains(visitor.LocalHitTestPoint, ENFillRule.EvenOdd);
     }
    ...
    }
    

    The path is hit-tested via its Contains method. The point used is the LocalHitTestPoint, which is in local coordinates for the current visual. Nearly all graphics objects and primitives  (NRectangle, NQuadrangle, NPolygon, NRegion, NGraphicsPath etc. implement a Contains methods). 

    Implementing Region Hit-Test

    As mentioned the bool HitTest(NRegionHitTestVisitor visitor) method is called during top-most or all region hit tests. The passed NRegionHitTestVisitor instance derives from NDisplayVisitor, and the hit-test region is available in two coordinate systems - local and scene, via the LocalHitTestRegion and SceneHitTestRegion properties respectively. In most cases you will use the region in local coordinates to perform a region hit test over a region in local coordinates. The following code hit-tests a graphics path that represents a doughnut shape by region:

    Implementing Region Hit Test
    Copy Code
    public class MyFirstVisual : NVisual
    {
     public override bool HitTest(NRegionHitTestVisitor visitor)
     {
      NGraphicsPath path = new NGraphicsPath();
      path.AddEllipse(0, 0, 100, 100);
      path.AddEllipse(10, 10, 80, 80);
      NRegion pathRegion = NRegion.FromPath(path, ENFillRule.EvenOdd);
      return pathRegion.IntersectsWith(visitor.LocalHitTestRegion);
     }
    }
    

    The region constructed from the path is hit-tested via its IntersectsWith method. The region used is the LocalHitTestRegion, which is in local coordinates for the current visual.

    The possibility to create a NRegion from a path (as well as other graphics objects) and to query whether it intersects with other regions, means that the region hit-test can be used for all types of area related hit-tests - from rectangular selection to lasso selection as well as all types of selection that are based on arbitrary geometry.

     

    See Also